import java.util.Collections;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * 连续重试N次
 *
 * @author Chris
 * @version 1.0.0
 * @date 2019/04/14
 * @since 1.0.0
 */
@Slf4j
public class TestRetryBackOffPolicy {
    private static void vpmsRetryCoupon(final String userId) {
        // 构建重试模板实例
        RetryTemplate retryTemplate = new RetryTemplate();
        // 设置重试策略，主要设置重试次数
        SimpleRetryPolicy policy = new SimpleRetryPolicy(5, Collections.singletonMap(Exception.class, true));

        // 指定时间等待策略，默认1s
        // FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // backOffPolicy.setBackOffPeriod(1000);

        // 无等待策略
        // NoBackOffPolicy backOffPolicy = new NoBackOffPolicy();

        // 指数级等待等待策略
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(100L);
        backOffPolicy.setMaxInterval(10000L);
        backOffPolicy.setMultiplier(2.0);

        // 指数级等待等待策略
        // ExponentialRandomBackOffPolicy backOffPolicy = new ExponentialRandomBackOffPolicy();
        // backOffPolicy.setInitialInterval(100L);
        // backOffPolicy.setMaxInterval(10000L);
        // bkOffPolicy.setMultiplier(2.0);

        // 指定范围内的随机等待
        // UniformRandomBackOffPolicy backOffPolicy = new UniformRandomBackOffPolicy();
        // backOffPolicy.setMinBackOffPeriod(500L);
        // backOffPolicy.setMaxBackOffPeriod(1500L);

        retryTemplate.setRetryPolicy(policy);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        // 通过RetryCallback 重试回调实例包装正常逻辑逻辑，第一次执行和重试执行执行的都是这段逻辑
        //RetryContext 重试操作上下文约定，统一spring-try包装
        final RetryCallback<Boolean, Exception> retryCallback = context -> {
            boolean result = pushCouponByVpmsaa(userId);
            if (!result) {
                // 这个点特别注意，重试的根源通过Exception返回
                throw new RuntimeException("fail, will retry.");
                // log.error("fail, will retry.");
                // return false;
            }
            return true;
        };
        // 通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例
        final RecoveryCallback<Boolean> recoveryCallback = context -> {
            log.info("正在重试发券::::::::::::" + userId);
            return null;
        };
        try {
            // 由retryTemplate 执行execute方法开始逻辑执行
            // Boolean execute = retryTemplate.execute(retryCallback, recoveryCallback);
            Boolean execute = retryTemplate.execute(retryCallback);
            System.out.println(execute);
        } catch (Exception e) {
            log.info("发券错误异常========" + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // test();
        // test(null);
        // test("public");
        vpmsRetryCoupon("43333");
    }

    private static Boolean pushCouponByVpmsaa(String userId) throws InterruptedException {
        Random random = new Random();
        int a = random.nextInt(10);
        System.out.println("a是" + a);
        TimeUnit.MILLISECONDS.sleep(500);
        if (a == 8) {
            throw new RuntimeException("fail, will retry.");
        }
        return false;
    }

    private static void test(String... permission) {
        if (Objects.nonNull(permission) && permission.length == 1 && StringUtils.equalsIgnoreCase("public", permission[0])) {
            System.out.println("bbbb");
        }
        System.out.println("aaaaa");

    }
}
